Alexa で Smart Home Skill を作るには
とりあえず作ってみる
アカウントの作成
ここでハマってしまいメチャクチャ時間が溶けた。
Amazon 関連のアカウントとしては、以下のようなものがある。
Amazon Developer で利用するアカウント
AWS で利用するアカウント
Amazon.co.jp で買い物をする時用のアカウント
一番問題があるのは Alexa アプリ のアカウント。Alexa は世界中で利用されていて、Alexa スキル/スキルストア/アプリ は各国のドメイン/ホストに結びついている。
alexa.amazon.com(米国)
alexa.amazon.co.jp(日本)
alexa.amazon.co.uk(英国)
alexa.amazon.de(独国)
alexa.amazon.in(インド)
で、Alexa アプリにログインするときのメールアドレスが、amazon.com で利用されていると、メールアドレス/パスワードの組が amazon.co.jp のものであっても、amazon.com へのログインになってしまう らしい。
Amazon Developer は amazon.com なので、Amazon Developer からアカウントを新規作成し、そのアカウントで Alexa スキルにログインするとホストが amazon.com となる。
あるいは、おそらく AWS アカウントと同じメールアドレスを利用して Alexa アプリにログインしても、AWS は amazon.com であるので、Alexa アプリのホストが amazon.com となってしまう。
しかし、Alexa アプリのホストが amazon.com となってしまった場合に何が問題なのか?というと...
Amazon Developer/Alexa アプリ間でホストが異なると、Amazon Developer で開発中のアプリが Alexa アプリから利用できない
Amazon Devloper/Alexa アプリ間でホストが同一でも、どちらも amazon.com になっていると、Lambda が invoke されない
自分は後者でかなりの時間ハマってしまった。なぜ lambda が invoke されなかったのかというと、Smart Home Skill には、サービスのエンドポイントと Lambda 関数の region の組に制限があるためである。例えば、日本の場合は Lambda はオレゴン region を利用する必要がある。
罠は二つある。
手元の Alexa アプリでは開発者アプリが見えている
表面上は、手元の Alexa アプリで開発者アプリが見えているのだが、なぜか「デバイスの検出」を行っても Lambda が invoke されず、CloudWatch Logs にも何も表示されなかった。開発者アプリが見えているのでとても厄介
Amazon Developer コンソール上では、Smart Home Skill のエンドポイントが日本になっているように見える
Amazon Developer コンソールのアカウント情報では、国・地域設定が「Japan」に設定されている
デフォルトエンドポイントにオレゴン region の lambda を設定しないとエラーを吐かれるためである
Amazon Developer コンソール自体は、スキルのエンドポイントが日本 (amazon.co.jp) であることを想定しているが、Alexa アプリは amazon.com をホストとしてログインしてしまう。さらに、Amazon Developer アカウントと同一のアカウントであれば、Amazon Developer アカウントの国・地域設定が Japan であっても、Alexa アプリamazon.com をホストとしてログインしてしまい、開発者スキルが利用できてしまう。
おそらく、Alexa アプリのホストが amazon.com だと、対応する lambda でないと呼び出されない。Amazon Developer コンソール上で Far East 用の lambda のみ設定していた場合には、対応する lambda がないので呼び出されない、ということになる。
注意すべきことは...
amazon.com に紐づいたメールアドレス (AWS や米国の amazon.com, Amazon Developer で新規作成したアカウントのメールアドレス) で、Amazon Developer コンソール、および Alexa アプリにログインしない
逆に、amazon.co.jp で利用しているメールアドレス/パスワードで、Amazon Developer コンソールにアクセスすると良い
AWS アカウントと Amazon Developer コンソールのアカウントは一致している必要はない
基本的には、Alexa アプリの、メールアドレスからサービス横断的にホストを判定する、という仕様があまりイケてないように思える...
作成手順
Amazon Developer コンソールにて、Smart Home Skill を作成する
Login with Amazon のセキュリティプロファイル の クライアントID, クライアントシークレット を設定する
Lambda をエンドポイントとして設定する
AWS にて、オレゴン (us-west-2) region の AWS Lambda を作成する
Smart Home Skill の ARN を、トリガーとして設定する
Amazon Developer コンソールにて、Login with Amazon のセキュリティプロファイル を作成する
Smart Home Skill のリダイレクト URL を、Web 設定の返信 URL に設定する
基本的には下記を参考にすればできる。
開発 API
ワークフロー
基本的に、Alexa Cloud から Directive が Lambda に送信されてくるので、それをハンドリングし、Alexa Cloud に Event を返す。応答は 8 秒以内に同期/非同期で返す必要があるが、時間がかかる操作の場合にも適切な対応を行えば適応できる。
https://gyazo.com/50c4c64202d35a28a873d5d490732f90
データ構造
Directive も Event も、基本構造は同じ。
ただし、Event には以下のオブジェクトが含まれる場合がある。
これら Directive, Event には、その機能に応じて決められた種類がいくつかある。例えば、デバイスの検出時に送信される Directive や、デバイスの電源のオンオフ、デバイスの温度制御時の Directive, Event は、基本構造は同じだが詳細な構造は異なる。Alexa Skills Kit では、これらが各々 機能インタフェース として定義されている。Directive や Event がどの機能インタフェースに属しているのかは、基本的には、Header の namespace, name を確認すればわかるようだ。
さらに、機能インタフェースにはサポートする プロパティ が存在する。例えば、Alexa.PowerController インタフェースは、powerState プロパティをサポートしている。
機能インタフェースの一覧は、以下から確認できる。
シーケンス
デバイスの検出
例えば、「デバイスの検出」が走った時は Alexa.Discovery インタフェースが利用される。Directive オブジェクトを返し、Header と Payload を含む。 code:json
{
"directive": {
"header": {
"namespace": "Alexa.Discovery",
"name": "Discover",
"payloadVersion": "3",
"messageId": "abc-123-def-456"
},
"payload": {
"scope": {
"type": "BearerToken",
"token": "access-token-from-skill"
}
}
}
}
これに対して、レスポンスは Discover.Response インタフェースを利用する。Header にて、名前空間 Alexa.Discovery に対し、名前を Discover.Response として返す。payload の中身については リファレンス を参照。Event オブジェクトを返し、Header と Payload を含む。 code:json
{
"event": {
"header": {
"namespace": "Alexa.Discovery",
"name": "Discover.Response",
"payloadVersion": "3",
"messageId": "abc-123-def-456"
},
"payload": {
"endpoints": [
{
"endpointId": "appliance-001",
"friendlyName": "リビングの照明",
"description": "サンプルメーカーのスマート照明",
"manufacturerName": "サンプルメーカー",
"displayCategories": [
"LIGHT"
],
"capabilities": [
...
電源のオン/オフ
code:json
{
"directive": {
"header": {
"namespace": "Alexa.PowerController",
"name": "TurnOff",
"payloadVersion": "3",
"messageId": "1bd5d003-31b9-476f-ad03-71d471922820",
"correlationToken": "dFMb0z+PgpgdDmluhJ1LddFvSqZ/jCc8ptlAKulUj90jSqg=="
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "access-token-from-skill"
},
"endpointId": "appliance-001",
"cookie": {}
},
"payload": {}
}
}
レスポンスは Event オブジェクトを返すが、同時に Context オブジェクトも返す。Event オブジェクトの Header は名前空間が Alexa、名前が Response となるが、一方 Context 内には元の header 情報を含んだ properties を含んでいる。
code:json
{
"context": {
"properties": [ {
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 500
} ]
},
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"payloadVersion": "3",
"messageId": "abc-123-def-456",
"correlationToken": "dFMb0z+PgpgdDmluhJ1LddFvSqZ/jCc8ptlAKulUj90jSqg=="
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "access-token-from-Amazon"
},
"endpointId": "appliance-001"
},
"payload": {}
}
}
エラー